package com.bubblegumproject.ogo.component.injection;

import com.bubblegumproject.ogo.action.Context;
import com.bubblegumproject.ogo.component.JavaBeanProperty;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * Implements a chain-of-responsibility pattern for many different {@link DependencyInjector}
 * objects.
 *
 * TODO: Must write tests for all dependency injection
 *
 * @author Azubuko Obele (buko.obele@gmail.com)
 */
public class DependencyInjectorChain {

    private List<DependencyInjector> injectors = new ArrayList<DependencyInjector>();

    public DependencyInjectorChain(DependencyInjector... injectors) {
        for (DependencyInjector di : injectors) {
            this.injectors.add(di);
        }
    }


    public void inject(Object component, Class componentClazz, Context context) {
        Collection<Injector> injectors = createInjectors(component, componentClazz);
        for (DependencyInjector di : this.injectors) {
            di.inject(injectors, context);
        }

        for (Injector injector : injectors) {
            if (!injector.isSatisfied()) {
                throw new IllegalStateException(this + " failed to satisfy injector " + injector);
            }
        }
    }

     protected Collection<Injector> createInjectors(Object component, Class componentClazz) {
        assert(componentClazz != null);
        Collection<Injector> injectors = new ArrayList<Injector>();
        for (Method method : componentClazz.getMethods()) {
            if (method.isAnnotationPresent(Inject.class)) {
                Inject inject = method.getAnnotation(Inject.class);
                JavaBeanProperty property = new JavaBeanProperty(method);
                injectors.add(new Injector(component, property, inject));
            }
        }
        return injectors;
    }
}


